# ##对功能进行封装就是面向过程编程
# 功能
# def login(username, passwd):
#     if username == "root" and passwd == "123456":
#         return True
#     else:
#         return False
#
#
# print(login("root", "123456"))


# ##把数据和功能结合起来，用称之为对象的东西把他包裹起来组织程序的方法就是面向对象编程
# class LoginCheck:
#
#     # 登陆数据
#     username = "root"
#     passwd = "123456"
#
#     # 登陆功能
#     def login(self, username, passwd):
#         if self.username == username and self.passwd == passwd:
#             return True
#         else:
#             return False
#
#
# lg1 = LoginCheck()
# print(lg1.login("root", "123456"))


# -------------------------------------------------------------------------------
# ##面向对象的基本概念
# python里面一切皆对象

# ##类
# 类(class):
# 用来描述具有相同属性和方法的对象的集合
# 车, 可以看成一个类
# 属性: 车的数据,方法:功能

# ##基类/子类
# 车(基类) / 摩托车,大卡车,小轿车(子类)

# ##对象
# 或者说实例: 具体的某个事物, 某个类型实实在在的一个例子
# 像小轿车的对象(实例)可以是奔驰, 可以是宝马

# ##类的实例化
# 类就相当于生成实例的工程
# 我们这个飞机(实例对象)的长度, 大小就是类里的属性(数据)
# 我们这个飞机(实例对象)的一些功能就是类里的方法(函数)


# ------------------------------------------------------------------------------------
# ATM机的存取款功能
# ATM角色  50000
# 用户角色  5000
# 1, 登陆功能
# 2, 菜单界面
#    1, 取款
#    2, 存款
#    3, 查询
# class ATM:
#     # 初始金额
#     Atm_money = 50000
#     User_money = 5000
#     username = "root"
#     passwd = "123456"
#
#     # 登陆
#     def login(self, username, passwd):
#         if self.username == username and self.passwd == passwd:
#             print("登陆成功!")
#             return True
#         else:
#             print("登陆失败!")
#             return False
#
#     # 菜单
#     def menu1(self):
#         print("**********")
#         print("1, 用户登陆")
#         print("2, 退出")
#         print("**********")
#
#     def menu2(self):
#         print("**********")
#         print("1, 存款")
#         print("2, 取款")
#         print("3, 查询账户")
#         print("4, 退出")
#         print("**********")
#
#     # 存款
#     def dep(self, deposit):
#         self.Atm_money += deposit
#         self.User_money += deposit
#
#     # 取款
#     def wit(self, withdrawal):
#         if withdrawal > self.User_money:
#             print("用户账号没有更多金额")
#         elif withdrawal > self.Atm_money:
#             print("ATM机没有更多金额")
#         else:
#             self.Atm_money -= withdrawal
#             self.User_money -= withdrawal
#
#
# wang = ATM()
# while True:
#     wang.menu1()
#     choice1 = input()
#     if choice1 == '1':
#         username = input("请输入用户名: ")
#         passwd = input("请输入用户密码: ")
#         if wang.login(username, passwd):
#             while True:
#                 wang.menu2()
#                 choice2 = input()
#                 if choice2 == '1':
#                     deposit = int(input("请输入存款金额: "))
#                     wang.dep(deposit)
#                 if choice2 == '2':
#                     withdrawal = int(input("请输入取款金额: "))
#                     wang.wit(withdrawal)
#                 if choice2 == '3':
#                     print("用户账户金额: ", wang.User_money)
#                 if choice2 == '4':
#                     break
#                 input("请按回车....")
#     else:
#         break


# ------------------------------------------------------------------------
# ##类的定义
# class A():
#     pass
#
# class B:
#     pass
#
# # object是python中自带的, 也可以指定, 指定后object就是基类
# # 继承
# class C(object):
#     pass

# 三者直接没有区别
# 新式类和经典类
# python2 => 有经典类和新式类, 继承object的都是新式类
# python3 => 都是新式类

# class Bus317(object):
#     # 类属性  --描述信息
#     line = "317"
#
#     # 方法 -- 》行为
#     def run(self, flag):
#         print("bus317 is run")
#         if flag == 0:
#             print("从农大到长华小区")
#         else:
#             print("从长华小区到农大")
#
#
# # 创建一个对象
# # 实例化
# bus01 = Bus317()
# bus02 = Bus317()
#
# # 打印类和实例的内存
# print(id(Bus317), id(bus01), id(bus02))
# # 类和实例都有单独的命名空间
#
# # 查看对象的属性或方法
# # 可以看到我们自己定义的属性和方法
# print(dir(bus01))
#
# # 使用对象的属性和方法
# bus01.run(0)
# bus02.run(1)
# print(bus01.line)
#
# # 直接用类访问属性, 直接访问类的方法是有问题的
# # Bus317.run(0)
# print(Bus317.line)


# -----------------------------------------------------------------------------------
# # 定义了__init__构造方法,并且构造方法需要传递一个参数
# # 实例化的时候传递参数给__init__方法:
# class Bus317(object):
#     # 类属性  --描述信息
#     line = "317"
#
#     def __init__(self, pro):
#         print("this is init")
#         self.pro = pro
#
#     # 方法 -- 》行为
#     def run(self, flag):
#         print("bus317 is run")
#         if flag == 0:
#             print("从农大到长华小区")
#         else:
#             print("从长华小区到农大")
#
#
# bus03 = Bus317("bmw")
# print(bus03.pro)

# ----------------------------------------------------------------------------------------
# ##类空间和实例空间
# 创建类的时候就会生成类空间（单独的内存空间）
# class Bus317(object):
#     line = "317"
#
#     def __init__(self, pro):
#         print("this is init")
#         self.pro = pro
#
#     # 方法 -- 》行为
#     def run(self, flag):
#         print("bus317 is run")
#         if flag == 0:
#             print("从农大到长华小区")
#         else:
#             print("从长华小区到农大")
#
#
# # 查看类空间有哪些东西
# # 类空间不定义实例属性的
# print(Bus317.__dict__)
#
# # 实例化对象
# bus01 = Bus317("byd")
# # 查看实例空间有哪些属性
# print(bus01.__dict__)
# print(bus01.line, bus01.pro)
# {'pro': 'byd'}
# 317 byd

# 那么line不是实例空间的，而是类空间的，那么为啥实例可以引用这个属性？
# 创建实例的时候，实例会自动创建一些指针指向类空间，帮实例空间访问到类空间
# 实例查找属性方法时，会先在实例空间查找，在到类空间查找，再到父类空间查找


# -------------------------------------------------------------
# # __new__方法
# class Bus317:
#     line = 10
#
#     def __init__(self, pro):
#         print("this is init method")
#         self.pro = pro
#
#     # cls接受到的参数就是当前类
#     def __new__(cls, *args, **kwargs):
#         print("this is new method")
#         # 返回实例
#         # return cls
#         # 如果不返回实例就不能使用属性和方法
#         # return "new"
#         return object.__new__(cls)
#
#     # __new__方法创建的实例传给__init__方法的self进行实例化
#
#
# bus01 = Bus317("aaa")
# print(bus01)
# print(bus01.line)
# print(bus01.pro)

# 总结：
# __new__是创建实例的方法
# __init__是创建好的实例，进行初始化工作的方法
# __new__方法必须传入一个参数（cls），代表当前类
# __new__必须返回一个实例化的对象
# __init__的self就表示__new__返回的实例，__init__对这个实例进行初始化工作
# 子类没有__new__，会去找父类（基类）的方法
# 新式类才有__new__
# 如果实例化对象和本身class不一致，__init__不会执行


# -------------------------------------------------------------
# 练习
class Students:

    school = "sdnu"

    def __init__(self, name, age, grade):
        self.name = name
        self.age = age
        self.grade = grade

    def total(self):
        # sum1 = 0
        # for i in self.grade.values():
        #     sum1 += i
        # return sum1
        return sum(self.grade.values())

    def average(self):
        # sum1 = 0
        # for i in self.grade.values():
        #     sum1 += i
        # return sum1 / len(self.grade)
        return sum(self.grade.values()) / len(self.grade)


grade = {"yuwen": 100, "suxue": 100, "yinyu": 100}
wang = Students("wangwenlong", 22, grade)
print("总分：", wang.total())
print(r"平均分：%.2f" % wang.average())
print(wang.name, wang.age, wang.school, wang.grade)
